🎖️GitЯра🎖️
Node / meshtastic / Meshtastic-Android / files / app / src / main / java / com / geeksville / mesh / model / MetricsViewModel.kt
Displaying Raw • Download
app/src/main/java/com/geeksville/mesh/model/MetricsViewModel.kt ui_message_list (be3f882f) Text, 17.37 KB
T8b949e/*
* Copyright (c) 2025 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
Tff7b72package T7ee787com.geeksville.mesh.model
Tff7b72import T7ee787android.app.Application
Tff7b72import T7ee787android.net.Uri
Tff7b72import T7ee787androidx.annotation.StringRes
Tff7b72import T7ee787androidx.compose.ui.unit.Dp
Tff7b72import T7ee787androidx.compose.ui.unit.dp
Tff7b72import T7ee787androidx.lifecycle.SavedStateHandle
Tff7b72import T7ee787androidx.lifecycle.ViewModel
Tff7b72import T7ee787androidx.lifecycle.viewModelScope
Tff7b72import T7ee787androidx.navigation.toRoute
Tff7b72import T7ee787com.geeksville.mesh.ConfigProtos.Config.DisplayConfig.DisplayUnits
Tff7b72import T7ee787com.geeksville.mesh.CoroutineDispatchers
Tff7b72import T7ee787com.geeksville.mesh.DataPacket
Tff7b72import T7ee787com.geeksville.mesh.MeshProtos
Tff7b72import T7ee787com.geeksville.mesh.MeshProtos.MeshPacket
Tff7b72import T7ee787com.geeksville.mesh.MeshProtos.Position
Tff7b72import T7ee787com.geeksville.mesh.Portnums
Tff7b72import T7ee787com.geeksville.mesh.Portnums.PortNum
Tff7b72import T7ee787com.geeksville.mesh.R
Tff7b72import T7ee787com.geeksville.mesh.TelemetryProtos.Telemetry
Tff7b72import T7ee787com.geeksville.mesh.android.Logging
Tff7b72import T7ee787com.geeksville.mesh.android.prefs.MapPrefs
Tff7b72import T7ee787com.geeksville.mesh.database.MeshLogRepository
Tff7b72import T7ee787com.geeksville.mesh.database.entity.FirmwareRelease
Tff7b72import T7ee787com.geeksville.mesh.database.entity.MeshLog
Tff7b72import T7ee787com.geeksville.mesh.model.map.CustomTileSource
Tff7b72import T7ee787com.geeksville.mesh.navigation.NodesRoutes
Tff7b72import T7ee787com.geeksville.mesh.repository.api.DeviceHardwareRepository
Tff7b72import T7ee787com.geeksville.mesh.repository.api.FirmwareReleaseRepository
Tff7b72import T7ee787com.geeksville.mesh.repository.datastore.RadioConfigRepository
Tff7b72import T7ee787com.geeksville.mesh.service.ServiceAction
Tff7b72import T7ee787com.geeksville.mesh.util.safeNumber
Tff7b72import T7ee787dagger.hilt.android.lifecycle.HiltViewModel
Tff7b72import T7ee787kotlinx.coroutines.flow.MutableStateFlow
Tff7b72import T7ee787kotlinx.coroutines.flow.StateFlow
Tff7b72import T7ee787kotlinx.coroutines.flow.asFlow
Tff7b72import T7ee787kotlinx.coroutines.flow.combine
Tff7b72import T7ee787kotlinx.coroutines.flow.distinctUntilChanged
Tff7b72import T7ee787kotlinx.coroutines.flow.filterNotNull
Tff7b72import T7ee787kotlinx.coroutines.flow.launchIn
Tff7b72import T7ee787kotlinx.coroutines.flow.map
Tff7b72import T7ee787kotlinx.coroutines.flow.mapLatest
Tff7b72import T7ee787kotlinx.coroutines.flow.onEach
Tff7b72import T7ee787kotlinx.coroutines.flow.toList
Tff7b72import T7ee787kotlinx.coroutines.flow.update
Tff7b72import T7ee787kotlinx.coroutines.launch
Tff7b72import T7ee787kotlinx.coroutines.withContext
Tff7b72import T7ee787java.io.BufferedWriter
Tff7b72import T7ee787java.io.FileNotFoundException
Tff7b72import T7ee787java.io.FileWriter
Tff7b72import T7ee787java.text.SimpleDateFormat
Tff7b72import T7ee787java.util.Locale
Tff7b72import T7ee787java.util.concurrent.TimeUnit
Tff7b72import T7ee787javax.inject.Inject
Tff7b72private Tff7b72const Tff7b72val Te6edf3DEFAULT_ID_SUFFIX_LENGTH Tff7b72= T79c0ff4
Tff7b72data Tff7b72class T56d364MetricsStateTb4b4b4(
Tff7b72val Te6edf3isLocalTb4b4b4: Tffa657Boolean Tff7b72= Tff7b72falseTb4b4b4,
Tff7b72val Te6edf3isManagedTb4b4b4: Tffa657Boolean Tff7b72= Tff7b72trueTb4b4b4,
Tff7b72val Te6edf3isFahrenheitTb4b4b4: Tffa657Boolean Tff7b72= Tff7b72falseTb4b4b4,
Tff7b72val Te6edf3displayUnitsTb4b4b4: Te6edf3DisplayUnits Tff7b72= Te6edf3DisplayUnitsTb4b4b4.Te6edf3METRICTb4b4b4,
Tff7b72val Te6edf3nodeTb4b4b4: Te6edf3Node? Tff7b72= Tff7b72nullTb4b4b4,
Tff7b72val Te6edf3deviceMetricsTb4b4b4: Te6edf3ListTff7b72<Te6edf3TelemetryTff7b72> Tff7b72= Te6edf3emptyListTb4b4b4(Tb4b4b4)Tb4b4b4,
Tff7b72val Te6edf3signalMetricsTb4b4b4: Te6edf3ListTff7b72<Te6edf3MeshPacketTff7b72> Tff7b72= Te6edf3emptyListTb4b4b4(Tb4b4b4)Tb4b4b4,
Tff7b72val Te6edf3powerMetricsTb4b4b4: Te6edf3ListTff7b72<Te6edf3TelemetryTff7b72> Tff7b72= Te6edf3emptyListTb4b4b4(Tb4b4b4)Tb4b4b4,
Tff7b72val Te6edf3hostMetricsTb4b4b4: Te6edf3ListTff7b72<Te6edf3TelemetryTff7b72> Tff7b72= Te6edf3emptyListTb4b4b4(Tb4b4b4)Tb4b4b4,
Tff7b72val Te6edf3tracerouteRequestsTb4b4b4: Te6edf3ListTff7b72<Te6edf3MeshLogTff7b72> Tff7b72= Te6edf3emptyListTb4b4b4(Tb4b4b4)Tb4b4b4,
Tff7b72val Te6edf3tracerouteResultsTb4b4b4: Te6edf3ListTff7b72<Te6edf3MeshLogTff7b72> Tff7b72= Te6edf3emptyListTb4b4b4(Tb4b4b4)Tb4b4b4,
Tff7b72val Te6edf3positionLogsTb4b4b4: Te6edf3ListTff7b72<Te6edf3PositionTff7b72> Tff7b72= Te6edf3emptyListTb4b4b4(Tb4b4b4)Tb4b4b4,
Tff7b72val Te6edf3deviceHardwareTb4b4b4: Te6edf3DeviceHardware? Tff7b72= Tff7b72nullTb4b4b4,
Tff7b72val Te6edf3isLocalDeviceTb4b4b4: Tffa657Boolean Tff7b72= Tff7b72falseTb4b4b4,
Tff7b72val Te6edf3firmwareEditionTb4b4b4: Te6edf3MeshProtosTb4b4b4.Te6edf3FirmwareEditionTff7b72? Tff7b72= Tff7b72nullTb4b4b4,
Tff7b72val Te6edf3latestStableFirmwareTb4b4b4: Te6edf3FirmwareRelease Tff7b72= Te6edf3FirmwareReleaseTb4b4b4(Tb4b4b4)Tb4b4b4,
Tff7b72val Te6edf3latestAlphaFirmwareTb4b4b4: Te6edf3FirmwareRelease Tff7b72= Te6edf3FirmwareReleaseTb4b4b4(Tb4b4b4)Tb4b4b4,
Tff7b72val Te6edf3paxMetricsTb4b4b4: Te6edf3ListTff7b72<Te6edf3MeshLogTff7b72> Tff7b72= Te6edf3emptyListTb4b4b4(Tb4b4b4)Tb4b4b4,
Tb4b4b4) Tb4b4b4{
Tff7b72fun Td2a8ffhasDeviceMetricsTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3deviceMetricsTb4b4b4.Te6edf3isNotEmptyTb4b4b4(Tb4b4b4)
Tff7b72fun Td2a8ffhasSignalMetricsTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3signalMetricsTb4b4b4.Te6edf3isNotEmptyTb4b4b4(Tb4b4b4)
Tff7b72fun Td2a8ffhasPowerMetricsTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3powerMetricsTb4b4b4.Te6edf3isNotEmptyTb4b4b4(Tb4b4b4)
Tff7b72fun Td2a8ffhasTracerouteLogsTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3tracerouteRequestsTb4b4b4.Te6edf3isNotEmptyTb4b4b4(Tb4b4b4)
Tff7b72fun Td2a8ffhasPositionLogsTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3positionLogsTb4b4b4.Te6edf3isNotEmptyTb4b4b4(Tb4b4b4)
Tff7b72fun Td2a8ffhasHostMetricsTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3hostMetricsTb4b4b4.Te6edf3isNotEmptyTb4b4b4(Tb4b4b4)
Tff7b72fun Td2a8ffhasPaxMetricsTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3paxMetricsTb4b4b4.Te6edf3isNotEmptyTb4b4b4(Tb4b4b4)
Tff7b72fun Td2a8ffdeviceMetricsFilteredTb4b4b4(Te6edf3timeFrameTb4b4b4: Te6edf3TimeFrameTb4b4b4)Tb4b4b4: Te6edf3ListTff7b72<Te6edf3TelemetryTff7b72> Tb4b4b4{
Tff7b72val Te6edf3oldestTime Tff7b72= Te6edf3timeFrameTb4b4b4.Te6edf3calculateOldestTimeTb4b4b4(Tb4b4b4)
Tff7b72return Te6edf3deviceMetricsTb4b4b4.Te6edf3filter Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3time Tff7b72>Tff7b72= Te6edf3oldestTime Tb4b4b4}
Tb4b4b4}
Tff7b72fun Td2a8ffsignalMetricsFilteredTb4b4b4(Te6edf3timeFrameTb4b4b4: Te6edf3TimeFrameTb4b4b4)Tb4b4b4: Te6edf3ListTff7b72<Te6edf3MeshPacketTff7b72> Tb4b4b4{
Tff7b72val Te6edf3oldestTime Tff7b72= Te6edf3timeFrameTb4b4b4.Te6edf3calculateOldestTimeTb4b4b4(Tb4b4b4)
Tff7b72return Te6edf3signalMetricsTb4b4b4.Te6edf3filter Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3rxTime Tff7b72>Tff7b72= Te6edf3oldestTime Tb4b4b4}
Tb4b4b4}
Tff7b72fun Td2a8ffpowerMetricsFilteredTb4b4b4(Te6edf3timeFrameTb4b4b4: Te6edf3TimeFrameTb4b4b4)Tb4b4b4: Te6edf3ListTff7b72<Te6edf3TelemetryTff7b72> Tb4b4b4{
Tff7b72val Te6edf3oldestTime Tff7b72= Te6edf3timeFrameTb4b4b4.Te6edf3calculateOldestTimeTb4b4b4(Tb4b4b4)
Tff7b72return Te6edf3powerMetricsTb4b4b4.Te6edf3filter Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3time Tff7b72>Tff7b72= Te6edf3oldestTime Tb4b4b4}
Tb4b4b4}
Tff7b72companion Tff7b72object Tb4b4b4{
Tff7b72val Te6edf3Empty Tff7b72= Te6edf3MetricsStateTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
T8b949e/** Supported time frames used to display data. */
Tf0883e@SuppressTb4b4b4(Ta5d6ff"Ta5d6ffMagicNumberTa5d6ff"Tb4b4b4)
Tff7b72enum Tff7b72class T56d364TimeFrameTb4b4b4(Tff7b72val Te6edf3secondsTb4b4b4: Tffa657LongTb4b4b4, Tf0883e@StringRes Tff7b72val Te6edf3strResTb4b4b4: Tffa657IntTb4b4b4) Tb4b4b4{
Te6edf3TWENTY_FOUR_HOURSTb4b4b4(Te6edf3TimeUnitTb4b4b4.Te6edf3DAYSTb4b4b4.Te6edf3toSecondsTb4b4b4(T79c0ff1Tb4b4b4)Tb4b4b4, Te6edf3RTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3twenty_four_hoursTb4b4b4)Tb4b4b4,
Te6edf3FORTY_EIGHT_HOURSTb4b4b4(Te6edf3TimeUnitTb4b4b4.Te6edf3DAYSTb4b4b4.Te6edf3toSecondsTb4b4b4(T79c0ff2Tb4b4b4)Tb4b4b4, Te6edf3RTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3forty_eight_hoursTb4b4b4)Tb4b4b4,
Te6edf3ONE_WEEKTb4b4b4(Te6edf3TimeUnitTb4b4b4.Te6edf3DAYSTb4b4b4.Te6edf3toSecondsTb4b4b4(T79c0ff7Tb4b4b4)Tb4b4b4, Te6edf3RTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3one_weekTb4b4b4)Tb4b4b4,
Te6edf3TWO_WEEKSTb4b4b4(Te6edf3TimeUnitTb4b4b4.Te6edf3DAYSTb4b4b4.Te6edf3toSecondsTb4b4b4(T79c0ff1T79c0ff4Tb4b4b4)Tb4b4b4, Te6edf3RTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3two_weeksTb4b4b4)Tb4b4b4,
Te6edf3FOUR_WEEKSTb4b4b4(Te6edf3TimeUnitTb4b4b4.Te6edf3DAYSTb4b4b4.Te6edf3toSecondsTb4b4b4(T79c0ff2T79c0ff8Tb4b4b4)Tb4b4b4, Te6edf3RTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3four_weeksTb4b4b4)Tb4b4b4,
Te6edf3MAXTb4b4b4(T79c0ff0LTb4b4b4, Te6edf3RTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3maxTb4b4b4)Tb4b4b4,
Tb4b4b4;
Tff7b72fun Td2a8ffcalculateOldestTimeTb4b4b4(Tb4b4b4)Tb4b4b4: Tffa657Long Tff7b72= Tff7b72if Tb4b4b4(Tff7b72this Tff7b72=Tff7b72= Te6edf3MAXTb4b4b4) Tb4b4b4{
Te6edf3MAXTb4b4b4.Te6edf3seconds
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3SystemTb4b4b4.Te6edf3currentTimeMillisTb4b4b4(Tb4b4b4) Tff7b72/ T79c0ff1T79c0ff0T79c0ff0T79c0ff0 Tff7b72- Tff7b72thisTb4b4b4.Te6edf3seconds
Tb4b4b4}
T8b949e/**
* The time interval to draw the vertical lines representing time on the x-axis.
*
* @return seconds epoch seconds
*/
Tff7b72fun Td2a8fflineIntervalTb4b4b4(Tb4b4b4)Tb4b4b4: Tffa657Long Tff7b72= Tff7b72when Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3ordinalTb4b4b4) Tb4b4b4{
Te6edf3TWENTY_FOUR_HOURSTb4b4b4.Te6edf3ordinal Tff7b72-Tff7b72> Te6edf3TimeUnitTb4b4b4.Te6edf3HOURSTb4b4b4.Te6edf3toSecondsTb4b4b4(T79c0ff6Tb4b4b4)
Te6edf3FORTY_EIGHT_HOURSTb4b4b4.Te6edf3ordinal Tff7b72-Tff7b72> Te6edf3TimeUnitTb4b4b4.Te6edf3HOURSTb4b4b4.Te6edf3toSecondsTb4b4b4(T79c0ff1T79c0ff2Tb4b4b4)
Te6edf3ONE_WEEKTb4b4b4.Te6edf3ordinalTb4b4b4,
Te6edf3TWO_WEEKSTb4b4b4.Te6edf3ordinalTb4b4b4,
Tff7b72-Tff7b72> Te6edf3TimeUnitTb4b4b4.Te6edf3DAYSTb4b4b4.Te6edf3toSecondsTb4b4b4(T79c0ff1Tb4b4b4)
Tff7b72else Tff7b72-Tff7b72> Te6edf3TimeUnitTb4b4b4.Te6edf3DAYSTb4b4b4.Te6edf3toSecondsTb4b4b4(T79c0ff7Tb4b4b4)
Tb4b4b4}
T8b949e/** Used to detect a significant time separation between [Telemetry]s. */
Tff7b72fun Td2a8fftimeThresholdTb4b4b4(Tb4b4b4)Tb4b4b4: Tffa657Long Tff7b72= Tff7b72when Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3ordinalTb4b4b4) Tb4b4b4{
Te6edf3TWENTY_FOUR_HOURSTb4b4b4.Te6edf3ordinal Tff7b72-Tff7b72> Te6edf3TimeUnitTb4b4b4.Te6edf3HOURSTb4b4b4.Te6edf3toSecondsTb4b4b4(T79c0ff6Tb4b4b4)
Te6edf3FORTY_EIGHT_HOURSTb4b4b4.Te6edf3ordinal Tff7b72-Tff7b72> Te6edf3TimeUnitTb4b4b4.Te6edf3HOURSTb4b4b4.Te6edf3toSecondsTb4b4b4(T79c0ff1T79c0ff2Tb4b4b4)
Tff7b72else Tff7b72-Tff7b72> Te6edf3TimeUnitTb4b4b4.Te6edf3DAYSTb4b4b4.Te6edf3toSecondsTb4b4b4(T79c0ff1Tb4b4b4)
Tb4b4b4}
T8b949e/**
* Calculates the needed [Dp] depending on the amount of time being plotted.
*
* @param time in seconds
*/
Tff7b72fun Td2a8ffdpTb4b4b4(Te6edf3screenWidthTb4b4b4: Tffa657IntTb4b4b4, Te6edf3timeTb4b4b4: Tffa657LongTb4b4b4)Tb4b4b4: Te6edf3Dp Tb4b4b4{
Tff7b72val Te6edf3timePerScreen Tff7b72= Tff7b72thisTb4b4b4.Te6edf3lineIntervalTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3multiplier Tff7b72= Te6edf3time Tff7b72/ Te6edf3timePerScreen
Tff7b72val Te6edf3dp Tff7b72= Tb4b4b4(Te6edf3screenWidth Tff7b72* Te6edf3multiplierTb4b4b4)Tb4b4b4.Te6edf3toIntTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3dp
Tff7b72return Te6edf3dpTb4b4b4.Te6edf3takeIf Tb4b4b4{ Tffa657it Tff7b72!Tff7b72= T79c0ff0.Te6edf3dp Tb4b4b4} Tff7b72?: Te6edf3screenWidthTb4b4b4.Te6edf3dp
Tb4b4b4}
Tb4b4b4}
Tff7b72private Tff7b72fun Te6edf3MeshPacketTb4b4b4.Td2a8ffhasValidSignalTb4b4b4(Tb4b4b4)Tb4b4b4: Tffa657Boolean Tff7b72=
Te6edf3rxTime Tff7b72> T79c0ff0 Tff7b72&Tff7b72& Tb4b4b4(Te6edf3rxSnr Tff7b72!Tff7b72= T79c0ff0f Tff7b72&Tff7b72& Te6edf3rxRssi Tff7b72!Tff7b72= T79c0ff0Tb4b4b4) Tff7b72&Tff7b72& Tb4b4b4(Te6edf3hopStart Tff7b72> T79c0ff0 Tff7b72&Tff7b72& Te6edf3hopStart Tff7b72- Te6edf3hopLimit Tff7b72=Tff7b72= T79c0ff0Tb4b4b4)
Tff7b72private Tff7b72fun Te6edf3MeshPacketTb4b4b4.Td2a8fftoPositionTb4b4b4(Tb4b4b4)Tb4b4b4: Te6edf3Position? Tff7b72= Tff7b72if Tb4b4b4(Tff7b72!Te6edf3decodedTb4b4b4.Te6edf3wantResponseTb4b4b4) Tb4b4b4{
Te6edf3runCatching Tb4b4b4{ Te6edf3PositionTb4b4b4.Te6edf3parseFromTb4b4b4(Te6edf3decodedTb4b4b4.Te6edf3payloadTb4b4b4) Tb4b4b4}Tb4b4b4.Te6edf3getOrNullTb4b4b4(Tb4b4b4)
Tb4b4b4} Tff7b72else Tb4b4b4{
Tff7b72null
Tb4b4b4}
Tf0883e@SuppressTb4b4b4(Ta5d6ff"Ta5d6ffLongParameterListTa5d6ff"Tb4b4b4)
Tf0883e@HiltViewModel
Tff7b72class T56d364MetricsViewModel
Tf0883e@Inject
Tff7b72constructorTb4b4b4(
Te6edf3savedStateHandleTb4b4b4: Te6edf3SavedStateHandleTb4b4b4,
Tff7b72private Tff7b72val Te6edf3appTb4b4b4: Te6edf3ApplicationTb4b4b4,
Tff7b72private Tff7b72val Te6edf3dispatchersTb4b4b4: Te6edf3CoroutineDispatchersTb4b4b4,
Tff7b72private Tff7b72val Te6edf3meshLogRepositoryTb4b4b4: Te6edf3MeshLogRepositoryTb4b4b4,
Tff7b72private Tff7b72val Te6edf3radioConfigRepositoryTb4b4b4: Te6edf3RadioConfigRepositoryTb4b4b4,
Tff7b72private Tff7b72val Te6edf3deviceHardwareRepositoryTb4b4b4: Te6edf3DeviceHardwareRepositoryTb4b4b4,
Tff7b72private Tff7b72val Te6edf3firmwareReleaseRepositoryTb4b4b4: Te6edf3FirmwareReleaseRepositoryTb4b4b4,
Tff7b72private Tff7b72val Te6edf3mapPrefsTb4b4b4: Te6edf3MapPrefsTb4b4b4,
Tb4b4b4) Tb4b4b4: Te6edf3ViewModelTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3Logging Tb4b4b4{
Tff7b72private Tff7b72val Te6edf3destNum Tff7b72= Te6edf3savedStateHandleTb4b4b4.Te6edf3toRouteTff7b72<Te6edf3NodesRoutesTb4b4b4.Te6edf3NodeDetailGraphTff7b72>Tb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3destNum
Tff7b72private Tff7b72fun Te6edf3MeshLogTb4b4b4.Td2a8ffhasValidTracerouteTb4b4b4(Tb4b4b4)Tb4b4b4: Tffa657Boolean Tff7b72=
Te6edf3withTb4b4b4(Te6edf3fromRadioTb4b4b4.Te6edf3packetTb4b4b4) Tb4b4b4{ Te6edf3hasDecodedTb4b4b4(Tb4b4b4) Tff7b72&Tff7b72& Te6edf3decodedTb4b4b4.Te6edf3wantResponse Tff7b72&Tff7b72& Te6edf3from Tff7b72=Tff7b72= T79c0ff0 Tff7b72&Tff7b72& Te6edf3to Tff7b72=Tff7b72= Te6edf3destNum Tb4b4b4}
T8b949e/**
* Creates a fallback node for hidden clients or nodes not yet in the database. This prevents the detail screen from
* freezing when viewing unknown nodes.
*/
Tff7b72private Tff7b72fun Td2a8ffcreateFallbackNodeTb4b4b4(Te6edf3nodeNumTb4b4b4: Tffa657IntTb4b4b4)Tb4b4b4: Te6edf3Node Tb4b4b4{
Tff7b72val Te6edf3userId Tff7b72= Te6edf3DataPacketTb4b4b4.Te6edf3nodeNumToDefaultIdTb4b4b4(Te6edf3nodeNumTb4b4b4)
Tff7b72val Te6edf3safeUserId Tff7b72= Te6edf3userIdTb4b4b4.Te6edf3padStartTb4b4b4(Te6edf3DEFAULT_ID_SUFFIX_LENGTHTb4b4b4, Ta5d6ff'0'Tb4b4b4)Tb4b4b4.Te6edf3takeLastTb4b4b4(Te6edf3DEFAULT_ID_SUFFIX_LENGTHTb4b4b4)
Tff7b72val Te6edf3longName Tff7b72= Te6edf3appTb4b4b4.Te6edf3getStringTb4b4b4(Te6edf3RTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3fallback_node_nameTb4b4b4, Te6edf3safeUserIdTb4b4b4)
Tff7b72val Te6edf3defaultUser Tff7b72=
Te6edf3MeshProtosTb4b4b4.Te6edf3UserTb4b4b4.Te6edf3newBuilderTb4b4b4(Tb4b4b4)
Tb4b4b4.Te6edf3setIdTb4b4b4(Te6edf3userIdTb4b4b4)
Tb4b4b4.Te6edf3setLongNameTb4b4b4(Te6edf3longNameTb4b4b4)
Tb4b4b4.Te6edf3setShortNameTb4b4b4(Te6edf3safeUserIdTb4b4b4)
Tb4b4b4.Te6edf3setHwModelTb4b4b4(Te6edf3MeshProtosTb4b4b4.Te6edf3HardwareModelTb4b4b4.Te6edf3UNSETTb4b4b4)
Tb4b4b4.Te6edf3buildTb4b4b4(Tb4b4b4)
Tff7b72return Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= Te6edf3nodeNumTb4b4b4, Te6edf3user Tff7b72= Te6edf3defaultUserTb4b4b4)
Tb4b4b4}
Tff7b72fun Td2a8ffgetUserTb4b4b4(Te6edf3nodeNumTb4b4b4: Tffa657IntTb4b4b4) Tff7b72= Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3getUserTb4b4b4(Te6edf3nodeNumTb4b4b4)
Tff7b72val Te6edf3tileSource
Tff7b72getTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3CustomTileSourceTb4b4b4.Te6edf3getTileSourceTb4b4b4(Te6edf3mapPrefsTb4b4b4.Te6edf3mapStyleTb4b4b4)
Tff7b72fun Td2a8ffdeleteLogTb4b4b4(Te6edf3uuidTb4b4b4: Tffa657StringTb4b4b4) Tff7b72= Te6edf3viewModelScopeTb4b4b4.Te6edf3launchTb4b4b4(Te6edf3dispatchersTb4b4b4.Te6edf3ioTb4b4b4) Tb4b4b4{ Te6edf3meshLogRepositoryTb4b4b4.Te6edf3deleteLogTb4b4b4(Te6edf3uuidTb4b4b4) Tb4b4b4}
Tff7b72fun Td2a8ffclearPositionTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3viewModelScopeTb4b4b4.Te6edf3launchTb4b4b4(Te6edf3dispatchersTb4b4b4.Te6edf3ioTb4b4b4) Tb4b4b4{
Te6edf3destNumTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3meshLogRepositoryTb4b4b4.Te6edf3deleteLogsTb4b4b4(Tffa657itTb4b4b4, Te6edf3PortNumTb4b4b4.Te6edf3POSITION_APP_VALUETb4b4b4) Tb4b4b4}
Tb4b4b4}
Tff7b72fun Td2a8ffonServiceActionTb4b4b4(Te6edf3actionTb4b4b4: Te6edf3ServiceActionTb4b4b4) Tff7b72= Te6edf3viewModelScopeTb4b4b4.Te6edf3launch Tb4b4b4{ Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3onServiceActionTb4b4b4(Te6edf3actionTb4b4b4) Tb4b4b4}
Tff7b72private Tff7b72val Te6edf3_state Tff7b72= Te6edf3MutableStateFlowTb4b4b4(Te6edf3MetricsStateTb4b4b4.Te6edf3EmptyTb4b4b4)
Tff7b72val Te6edf3stateTb4b4b4: Te6edf3StateFlowTff7b72<Te6edf3MetricsStateTff7b72> Tff7b72= Te6edf3_state
Tff7b72private Tff7b72val Te6edf3_environmentState Tff7b72= Te6edf3MutableStateFlowTb4b4b4(Te6edf3EnvironmentMetricsStateTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3environmentStateTb4b4b4: Te6edf3StateFlowTff7b72<Te6edf3EnvironmentMetricsStateTff7b72> Tff7b72= Te6edf3_environmentState
Tff7b72private Tff7b72val Te6edf3_timeFrame Tff7b72= Te6edf3MutableStateFlowTb4b4b4(Te6edf3TimeFrameTb4b4b4.Te6edf3TWENTY_FOUR_HOURSTb4b4b4)
Tff7b72val Te6edf3timeFrameTb4b4b4: Te6edf3StateFlowTff7b72<Te6edf3TimeFrameTff7b72> Tff7b72= Te6edf3_timeFrame
Tff7b72init Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3destNum Tff7b72!Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3nodeDBbyNum
Tb4b4b4.Te6edf3mapLatest Tb4b4b4{ Te6edf3nodes Tff7b72-Tff7b72> Te6edf3nodesTff7b72[Te6edf3destNumTff7b72] Te6edf3to Te6edf3nodesTb4b4b4.Te6edf3keysTb4b4b4.Te6edf3firstOrNullTb4b4b4(Tb4b4b4) Tb4b4b4}
Tb4b4b4.Te6edf3distinctUntilChangedTb4b4b4(Tb4b4b4)
Tb4b4b4.Te6edf3onEach Tb4b4b4{ Tb4b4b4(Te6edf3nodeTb4b4b4, Te6edf3ourNodeTb4b4b4) Tff7b72-Tff7b72>
T8b949e// Create a fallback node if not found in database (for hidden clients, etc.)
Tff7b72val Te6edf3actualNode Tff7b72= Te6edf3node Tff7b72?: Te6edf3createFallbackNodeTb4b4b4(Te6edf3destNumTb4b4b4)
Tff7b72val Te6edf3deviceHardware Tff7b72=
Te6edf3actualNodeTb4b4b4.Te6edf3userTb4b4b4.Te6edf3hwModelTb4b4b4.Te6edf3safeNumberTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3let Tb4b4b4{
Te6edf3deviceHardwareRepositoryTb4b4b4.Te6edf3getDeviceHardwareByModelTb4b4b4(Tffa657itTb4b4b4)
Tb4b4b4}
Te6edf3_stateTb4b4b4.Te6edf3update Tb4b4b4{ Te6edf3state Tff7b72-Tff7b72>
Te6edf3stateTb4b4b4.Te6edf3copyTb4b4b4(
Te6edf3node Tff7b72= Te6edf3actualNodeTb4b4b4,
Te6edf3isLocal Tff7b72= Te6edf3destNum Tff7b72=Tff7b72= Te6edf3ourNodeTb4b4b4,
Te6edf3deviceHardware Tff7b72= Te6edf3deviceHardwareTb4b4b4.Te6edf3getOrNullTb4b4b4(Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4.Te6edf3launchInTb4b4b4(Te6edf3viewModelScopeTb4b4b4)
Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3deviceProfileFlow
Tb4b4b4.Te6edf3onEach Tb4b4b4{ Te6edf3profile Tff7b72-Tff7b72>
Tff7b72val Te6edf3moduleConfig Tff7b72= Te6edf3profileTb4b4b4.Te6edf3moduleConfig
Te6edf3_stateTb4b4b4.Te6edf3update Tb4b4b4{ Te6edf3state Tff7b72-Tff7b72>
Te6edf3stateTb4b4b4.Te6edf3copyTb4b4b4(
Te6edf3isManaged Tff7b72= Te6edf3profileTb4b4b4.Te6edf3configTb4b4b4.Te6edf3securityTb4b4b4.Te6edf3isManagedTb4b4b4,
Te6edf3isFahrenheit Tff7b72= Te6edf3moduleConfigTb4b4b4.Te6edf3telemetryTb4b4b4.Te6edf3environmentDisplayFahrenheitTb4b4b4,
Te6edf3displayUnits Tff7b72= Te6edf3profileTb4b4b4.Te6edf3configTb4b4b4.Te6edf3displayTb4b4b4.Te6edf3unitsTb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4.Te6edf3launchInTb4b4b4(Te6edf3viewModelScopeTb4b4b4)
Te6edf3meshLogRepository
Tb4b4b4.Te6edf3getTelemetryFromTb4b4b4(Te6edf3destNumTb4b4b4)
Tb4b4b4.Te6edf3onEach Tb4b4b4{ Te6edf3telemetry Tff7b72-Tff7b72>
Te6edf3_stateTb4b4b4.Te6edf3update Tb4b4b4{ Te6edf3state Tff7b72-Tff7b72>
Te6edf3stateTb4b4b4.Te6edf3copyTb4b4b4(
Te6edf3deviceMetrics Tff7b72= Te6edf3telemetryTb4b4b4.Te6edf3filter Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3hasDeviceMetricsTb4b4b4(Tb4b4b4) Tb4b4b4}Tb4b4b4,
Te6edf3powerMetrics Tff7b72= Te6edf3telemetryTb4b4b4.Te6edf3filter Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3hasPowerMetricsTb4b4b4(Tb4b4b4) Tb4b4b4}Tb4b4b4,
Te6edf3hostMetrics Tff7b72= Te6edf3telemetryTb4b4b4.Te6edf3filter Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3hasHostMetricsTb4b4b4(Tb4b4b4) Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tb4b4b4}
Te6edf3_environmentStateTb4b4b4.Te6edf3update Tb4b4b4{ Te6edf3state Tff7b72-Tff7b72>
Te6edf3stateTb4b4b4.Te6edf3copyTb4b4b4(
Te6edf3environmentMetrics Tff7b72=
Te6edf3telemetryTb4b4b4.Te6edf3filter Tb4b4b4{
Tffa657itTb4b4b4.Te6edf3hasEnvironmentMetricsTb4b4b4(Tb4b4b4) Tff7b72&Tff7b72&
Tffa657itTb4b4b4.Te6edf3environmentMetricsTb4b4b4.Te6edf3hasRelativeHumidityTb4b4b4(Tb4b4b4) Tff7b72&Tff7b72&
Tffa657itTb4b4b4.Te6edf3environmentMetricsTb4b4b4.Te6edf3hasTemperatureTb4b4b4(Tb4b4b4) Tff7b72&Tff7b72&
Tff7b72!Tffa657itTb4b4b4.Te6edf3environmentMetricsTb4b4b4.Te6edf3temperatureTb4b4b4.Te6edf3isNaNTb4b4b4(Tb4b4b4)
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4.Te6edf3launchInTb4b4b4(Te6edf3viewModelScopeTb4b4b4)
Te6edf3meshLogRepository
Tb4b4b4.Te6edf3getMeshPacketsFromTb4b4b4(Te6edf3destNumTb4b4b4)
Tb4b4b4.Te6edf3onEach Tb4b4b4{ Te6edf3meshPackets Tff7b72-Tff7b72>
Te6edf3_stateTb4b4b4.Te6edf3update Tb4b4b4{ Te6edf3state Tff7b72-Tff7b72> Te6edf3stateTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3signalMetrics Tff7b72= Te6edf3meshPacketsTb4b4b4.Te6edf3filter Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3hasValidSignalTb4b4b4(Tb4b4b4) Tb4b4b4}Tb4b4b4) Tb4b4b4}
Tb4b4b4}
Tb4b4b4.Te6edf3launchInTb4b4b4(Te6edf3viewModelScopeTb4b4b4)
Te6edf3combineTb4b4b4(
Te6edf3meshLogRepositoryTb4b4b4.Te6edf3getLogsFromTb4b4b4(Te6edf3nodeNum Tff7b72= T79c0ff0Tb4b4b4, Te6edf3PortNumTb4b4b4.Te6edf3TRACEROUTE_APP_VALUETb4b4b4)Tb4b4b4,
Te6edf3meshLogRepositoryTb4b4b4.Te6edf3getLogsFromTb4b4b4(Te6edf3destNum Tff7b72?: T79c0ff0Tb4b4b4, Te6edf3PortNumTb4b4b4.Te6edf3TRACEROUTE_APP_VALUETb4b4b4)Tb4b4b4,
Tb4b4b4) Tb4b4b4{ Te6edf3requestTb4b4b4, Te6edf3response Tff7b72-Tff7b72>
Te6edf3_stateTb4b4b4.Te6edf3update Tb4b4b4{ Te6edf3state Tff7b72-Tff7b72>
Te6edf3stateTb4b4b4.Te6edf3copyTb4b4b4(
Te6edf3tracerouteRequests Tff7b72= Te6edf3requestTb4b4b4.Te6edf3filter Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3hasValidTracerouteTb4b4b4(Tb4b4b4) Tb4b4b4}Tb4b4b4,
Te6edf3tracerouteResults Tff7b72= Te6edf3responseTb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4.Te6edf3launchInTb4b4b4(Te6edf3viewModelScopeTb4b4b4)
Te6edf3meshLogRepository
Tb4b4b4.Te6edf3getMeshPacketsFromTb4b4b4(Te6edf3destNumTb4b4b4, Te6edf3PortNumTb4b4b4.Te6edf3POSITION_APP_VALUETb4b4b4)
Tb4b4b4.Te6edf3onEach Tb4b4b4{ Te6edf3packets Tff7b72-Tff7b72>
Tff7b72val Te6edf3distinctPositions Tff7b72=
Te6edf3packets
Tb4b4b4.Te6edf3mapNotNull Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3toPositionTb4b4b4(Tb4b4b4) Tb4b4b4}
Tb4b4b4.Te6edf3asFlowTb4b4b4(Tb4b4b4)
Tb4b4b4.Te6edf3distinctUntilChanged Tb4b4b4{ Te6edf3oldTb4b4b4, Te6edf3new Tff7b72-Tff7b72>
Te6edf3oldTb4b4b4.Te6edf3time Tff7b72=Tff7b72= Te6edf3newTb4b4b4.Te6edf3time Tff7b72|Tff7b72|
Tb4b4b4(Te6edf3oldTb4b4b4.Te6edf3latitudeI Tff7b72=Tff7b72= Te6edf3newTb4b4b4.Te6edf3latitudeI Tff7b72&Tff7b72& Te6edf3oldTb4b4b4.Te6edf3longitudeI Tff7b72=Tff7b72= Te6edf3newTb4b4b4.Te6edf3longitudeITb4b4b4)
Tb4b4b4}
Tb4b4b4.Te6edf3toListTb4b4b4(Tb4b4b4)
Te6edf3_stateTb4b4b4.Te6edf3update Tb4b4b4{ Te6edf3state Tff7b72-Tff7b72> Te6edf3stateTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3positionLogs Tff7b72= Te6edf3distinctPositionsTb4b4b4) Tb4b4b4}
Tb4b4b4}
Tb4b4b4.Te6edf3launchInTb4b4b4(Te6edf3viewModelScopeTb4b4b4)
Te6edf3meshLogRepository
Tb4b4b4.Te6edf3getLogsFromTb4b4b4(Te6edf3destNumTb4b4b4, Te6edf3PortnumsTb4b4b4.Te6edf3PortNumTb4b4b4.Te6edf3PAXCOUNTER_APP_VALUETb4b4b4)
Tb4b4b4.Te6edf3onEach Tb4b4b4{ Te6edf3logs Tff7b72-Tff7b72> Te6edf3_stateTb4b4b4.Te6edf3update Tb4b4b4{ Te6edf3state Tff7b72-Tff7b72> Te6edf3stateTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3paxMetrics Tff7b72= Te6edf3logsTb4b4b4) Tb4b4b4} Tb4b4b4}
Tb4b4b4.Te6edf3launchInTb4b4b4(Te6edf3viewModelScopeTb4b4b4)
Te6edf3firmwareReleaseRepositoryTb4b4b4.Te6edf3stableRelease
Tb4b4b4.Te6edf3filterNotNullTb4b4b4(Tb4b4b4)
Tb4b4b4.Te6edf3onEach Tb4b4b4{ Te6edf3latestStable Tff7b72-Tff7b72> Te6edf3_stateTb4b4b4.Te6edf3update Tb4b4b4{ Te6edf3state Tff7b72-Tff7b72> Te6edf3stateTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3latestStableFirmware Tff7b72= Te6edf3latestStableTb4b4b4) Tb4b4b4} Tb4b4b4}
Tb4b4b4.Te6edf3launchInTb4b4b4(Te6edf3viewModelScopeTb4b4b4)
Te6edf3firmwareReleaseRepositoryTb4b4b4.Te6edf3alphaRelease
Tb4b4b4.Te6edf3filterNotNullTb4b4b4(Tb4b4b4)
Tb4b4b4.Te6edf3onEach Tb4b4b4{ Te6edf3latestAlpha Tff7b72-Tff7b72> Te6edf3_stateTb4b4b4.Te6edf3update Tb4b4b4{ Te6edf3state Tff7b72-Tff7b72> Te6edf3stateTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3latestAlphaFirmware Tff7b72= Te6edf3latestAlphaTb4b4b4) Tb4b4b4} Tb4b4b4}
Tb4b4b4.Te6edf3launchInTb4b4b4(Te6edf3viewModelScopeTb4b4b4)
Te6edf3meshLogRepository
Tb4b4b4.Te6edf3getMyNodeInfoTb4b4b4(Tb4b4b4)
Tb4b4b4.Te6edf3map Tb4b4b4{ Tffa657itTff7b72?.Te6edf3firmwareEdition Tb4b4b4}
Tb4b4b4.Te6edf3distinctUntilChangedTb4b4b4(Tb4b4b4)
Tb4b4b4.Te6edf3onEach Tb4b4b4{ Te6edf3firmwareEdition Tff7b72-Tff7b72> Te6edf3_stateTb4b4b4.Te6edf3update Tb4b4b4{ Te6edf3state Tff7b72-Tff7b72> Te6edf3stateTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3firmwareEdition Tff7b72= Te6edf3firmwareEditionTb4b4b4) Tb4b4b4} Tb4b4b4}
Tb4b4b4.Te6edf3launchInTb4b4b4(Te6edf3viewModelScopeTb4b4b4)
Te6edf3debugTb4b4b4(Ta5d6ff"Ta5d6ffMetricsViewModel createdTa5d6ff"Tb4b4b4)
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3debugTb4b4b4(Ta5d6ff"Ta5d6ffMetricsViewModel: destNum is null, skipping metrics flows initialization.Ta5d6ff"Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tff7b72override Tff7b72fun Td2a8ffonClearedTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72superTb4b4b4.Te6edf3onClearedTb4b4b4(Tb4b4b4)
Te6edf3debugTb4b4b4(Ta5d6ff"Ta5d6ffMetricsViewModel clearedTa5d6ff"Tb4b4b4)
Tb4b4b4}
Tff7b72fun Td2a8ffsetTimeFrameTb4b4b4(Te6edf3timeFrameTb4b4b4: Te6edf3TimeFrameTb4b4b4) Tb4b4b4{
Te6edf3_timeFrameTb4b4b4.Te6edf3value Tff7b72= Te6edf3timeFrame
Tb4b4b4}
T8b949e/** Write the persisted Position data out to a CSV file in the specified location. */
Tff7b72fun Td2a8ffsavePositionCSVTb4b4b4(Te6edf3uriTb4b4b4: Te6edf3UriTb4b4b4) Tff7b72= Te6edf3viewModelScopeTb4b4b4.Te6edf3launchTb4b4b4(Te6edf3dispatchersTb4b4b4.Te6edf3mainTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3positions Tff7b72= Te6edf3stateTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3positionLogs
Te6edf3writeToUriTb4b4b4(Te6edf3uriTb4b4b4) Tb4b4b4{ Te6edf3writer Tff7b72-Tff7b72>
Te6edf3writerTb4b4b4.Te6edf3appendLineTb4b4b4(
Ta5d6ff"Ta5d6ff\"Ta5d6ffdateTa5d6ff\"Ta5d6ff,Ta5d6ff\"Ta5d6fftimeTa5d6ff\"Ta5d6ff,Ta5d6ff\"Ta5d6fflatitudeTa5d6ff\"Ta5d6ff,Ta5d6ff\"Ta5d6fflongitudeTa5d6ff\"Ta5d6ff,Ta5d6ff\"Ta5d6ffaltitudeTa5d6ff\"Ta5d6ff,Ta5d6ff\"Ta5d6ffsatsInViewTa5d6ff\"Ta5d6ff,Ta5d6ff\"Ta5d6ffspeedTa5d6ff\"Ta5d6ff,Ta5d6ff\"Ta5d6ffheadingTa5d6ff\"Ta5d6ff"Tb4b4b4,
Tb4b4b4)
Tff7b72val Te6edf3dateFormat Tff7b72= Te6edf3SimpleDateFormatTb4b4b4(Ta5d6ff"Ta5d6ff\"Ta5d6ffyyyy-MM-ddTa5d6ff\"Ta5d6ff,Ta5d6ff\"Ta5d6ffHH:mm:ssTa5d6ff\"Ta5d6ff"Tb4b4b4, Te6edf3LocaleTb4b4b4.Te6edf3getDefaultTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3positionsTb4b4b4.Te6edf3forEach Tb4b4b4{ Te6edf3position Tff7b72-Tff7b72>
Tff7b72val Te6edf3rxDateTime Tff7b72= Te6edf3dateFormatTb4b4b4.Te6edf3formatTb4b4b4(Te6edf3positionTb4b4b4.Te6edf3time Tff7b72* T79c0ff1T79c0ff0T79c0ff0T79c0ff0LTb4b4b4)
Tff7b72val Te6edf3latitude Tff7b72= Te6edf3positionTb4b4b4.Te6edf3latitudeI Tff7b72* T79c0ff1e-7
Tff7b72val Te6edf3longitude Tff7b72= Te6edf3positionTb4b4b4.Te6edf3longitudeI Tff7b72* T79c0ff1e-7
Tff7b72val Te6edf3altitude Tff7b72= Te6edf3positionTb4b4b4.Te6edf3altitude
Tff7b72val Te6edf3satsInView Tff7b72= Te6edf3positionTb4b4b4.Te6edf3satsInView
Tff7b72val Te6edf3speed Tff7b72= Te6edf3positionTb4b4b4.Te6edf3groundSpeed
Tff7b72val Te6edf3heading Tff7b72= Ta5d6ff"Ta5d6ff%.2fTa5d6ff"Tb4b4b4.Te6edf3formatTb4b4b4(Te6edf3positionTb4b4b4.Te6edf3groundTrack Tff7b72* T79c0ff1e-5Tb4b4b4)
T8b949e// date,time,latitude,longitude,altitude,satsInView,speed,heading
Te6edf3writerTb4b4b4.Te6edf3appendLineTb4b4b4(
Ta5d6ff"Tffd700$Te6edf3rxDateTimeTa5d6ff,Ta5d6ff\"Tffd700$Te6edf3latitudeTa5d6ff\"Ta5d6ff,Ta5d6ff\"Tffd700$Te6edf3longitudeTa5d6ff\"Ta5d6ff,Ta5d6ff\"Tffd700$Te6edf3altitudeTa5d6ff\"Ta5d6ff,Ta5d6ff\"Tffd700$Te6edf3satsInViewTa5d6ff\"Ta5d6ff,Ta5d6ff\"Tffd700$Te6edf3speedTa5d6ff\"Ta5d6ff,Ta5d6ff\"Tffd700$Te6edf3headingTa5d6ff\"Ta5d6ff"Tb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tff7b72private Tff7b72suspend Tff7b72inline Tff7b72fun Td2a8ffwriteToUriTb4b4b4(Te6edf3uriTb4b4b4: Te6edf3UriTb4b4b4, Te6edf3crossinline Te6edf3blockTb4b4b4: Te6edf3suspend Tb4b4b4(Te6edf3BufferedWriterTb4b4b4) Tff7b72-Tff7b72> Tffa657UnitTb4b4b4) Tff7b72=
Te6edf3withContextTb4b4b4(Te6edf3dispatchersTb4b4b4.Te6edf3ioTb4b4b4) Tb4b4b4{
Tff7b72try Tb4b4b4{
Te6edf3appTb4b4b4.Te6edf3contentResolverTb4b4b4.Te6edf3openFileDescriptorTb4b4b4(Te6edf3uriTb4b4b4, Ta5d6ff"Ta5d6ffwtTa5d6ff"Tb4b4b4)Tff7b72?.Te6edf3use Tb4b4b4{ Te6edf3parcelFileDescriptor Tff7b72-Tff7b72>
Te6edf3FileWriterTb4b4b4(Te6edf3parcelFileDescriptorTb4b4b4.Te6edf3fileDescriptorTb4b4b4)Tb4b4b4.Te6edf3use Tb4b4b4{ Te6edf3fileWriter Tff7b72-Tff7b72>
Te6edf3BufferedWriterTb4b4b4(Te6edf3fileWriterTb4b4b4)Tb4b4b4.Te6edf3use Tb4b4b4{ Te6edf3writer Tff7b72-Tff7b72> Te6edf3blockTb4b4b4.Te6edf3invokeTb4b4b4(Te6edf3writerTb4b4b4) Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3exTb4b4b4: Te6edf3FileNotFoundExceptionTb4b4b4) Tb4b4b4{
Te6edf3errormsgTb4b4b4(Ta5d6ff"Ta5d6ffCan't write file error: Tffd700${Te6edf3exTb4b4b4.Te6edf3messageTffd700}Ta5d6ff"Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Served by rngit 1.5.0 - Generated in 0.17s